package org.ccay.web.support.filter;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.ccay.core.exception.ApplicationException;
import org.ccay.core.ioc.Ccay;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.log.ILogger;
import org.ccay.core.request.impl.RequestContextConstants;
import org.ccay.core.util.EncodingUtil;
import org.ccay.core.util.StringUtil;
import org.ccay.registry.util.RegistryQueryUtil;
import org.ccay.web.support.EnvironmentBean;
import org.ccay.web.support.WebRequestVO;
import org.ccay.web.support.internal.IHostDomainHandler;
import org.ccay.web.support.internal.IResourceHandler;
import org.ccay.web.support.internal.impl.RequestUtil;

/**
 * 资源过滤器，用于读取HTML/JAVASCRIPT/CSS/图片等资源
 */
public final class ResourceFilter implements Filter {
	private static final ILogger logger = CcayLoggerFactory.getLogger(ResourceFilter.class);

	private static final String KEY_RESOUTCEFILTER_INITPARAS_PUBLIC = "public";

	private static final String KEY_RESOUTCEFILTER_INITPARAS_EXCLUDE = "exclude";

	private String[] exclusions = null;

	private String[] publices = null;

	private EnvironmentBean env;

//	private IPersonalPermissionService permissionService;
//
//	private ApplicationStateHandler applicationStateHandler;

	private IHostDomainHandler hostDomainHandler;

	/*
	 * （非 Javadoc)
	 * 
	 * @see javax.servlet.Filter#destroy()
	 */
	public void destroy() {
	}

	/**
	 * @description 该过滤器用来读取jar包中的静态资源。通过URL得到web请求地址，并通过ClassLoader加载文件输出值客户端
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
	 *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
			ServletException {
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		String shortUri = RequestUtil.getShortUri(httpRequest);

		//防止CSRF漏洞,不在域白名单中URL请求直接返回
		StringBuffer url = httpRequest.getRequestURL();

		// 判读返回的URL域名是否在域名白名单中
		boolean isInclude = hostDomainHandler.containsHostDomain(url.toString());

		// 如果返回的域名不在白名单中，则直接返回
		if(!isInclude) return;


		if (!RequestUtil.isResource(httpRequest)) {
			//service
			String ccayVersion = request.getParameter("ccayVersion");
			// 设置服务缓存大小
			if (ccayVersion != null && "GET".equalsIgnoreCase(httpRequest.getMethod())) {
				WebRequestVO webRequest = new WebRequestVO();
				webRequest.setFileType(RequestContextConstants.TYPE_PRIVATE_SERVICES);
				ResponseUtil.setCache4Resource(httpResponse, webRequest);
			} else {
				ResponseUtil.setCache4Service(httpRequest, httpResponse);
			}
			chain.doFilter(request, response);
			return;
		}
		if (shortUri.length() == 0) {
			// 兼容WAS8.5
			httpResponse.sendRedirect(RequestUtil.getContextPath(httpRequest));
			return;
		}
		String realUri = "/".equals(shortUri) ? "/" + env.getHomePath() : removeVersion(shortUri);

		realUri = URLDecoder.decode(realUri, EncodingUtil.UTF_8);

		/**
		 * TODO 判断释放系统变更中 如果是报异常
		 */
		//applicationStateHandler.keepOn(realUri);

		// 如果访问根，则默认跳转到 web.support/index.html，否则访问请求路径
		String filePath = "web" + realUri;

		logger.trace("Before read resource [{0}].", shortUri);

		WebRequestVO webRequest = new WebRequestVO();
		webRequest.setFileType(getFileType(filePath));
		webRequest.setShortUri(realUri);
		webRequest.setFilePath(filePath);
		webRequest.setLastModified(RequestUtil.getModifiedTimestamp(httpRequest));
		// 检查是否是例外或者没有文件类型的 不需要Resource帮助加载资源
		if (RequestUtil.isExclude(webRequest, this.exclusions)) {
			chain.doFilter(request, response);
			return;
		}

		// 设置缓存时间
		if(!shortUri.equals("/")){
			ResponseUtil.setCache4Resource(httpResponse, webRequest);
		}else{
			//首页固定设置缓存时间为1s
			if (RegistryQueryUtil.getBooleanValue("Ccay.GlobalParamters.EnableHomeCache")) {
				ResponseUtil.setCache(httpResponse, RegistryQueryUtil.getIntegerValue("Ccay.GlobalParamters.CacheControlMaxAge"));
			} else {
				//首页固定设置缓存时间为1s
				httpResponse.setHeader("Cache-Control", "max-age=1");
			}
		}
		// 设置ContentType
		ResponseUtil.setContentType(httpResponse, webRequest.getFileType());

		try {
			sendResource2Response(httpRequest, httpResponse, webRequest);
		} catch (ApplicationException e) {
			throw new ServletException(e);
		}
	}

	/**
	 * 所有可用的资源处理器集合
	 */
	@SuppressWarnings("unchecked")
	private static List<IResourceHandler> resHandlers = (List<IResourceHandler>) Ccay.getContext().getBean(
			"resourceHandlerList", List.class);

	private void sendResource2Response(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
			WebRequestVO webRequest) throws IOException, ApplicationException {
		for (IResourceHandler resHandler : resHandlers) {
			resHandler.sendResourceToResponse(httpRequest, httpResponse, webRequest);

			if (webRequest.isHandled()) {
				return;
			}
		}
	}

	/**
	 * 删除版本
	 * @param shortUri
	 * @return
	 */
	private String removeVersion(String shortUri) {
		int vStart = shortUri.lastIndexOf("((");
		if (vStart == -1) {
			return shortUri;
		}
		int vEnd = shortUri.lastIndexOf("))");
		return shortUri.substring(0, vStart) + shortUri.substring(vEnd + 2);
	}

	/**
	 * 获取文件类型
	 * @param filePath
	 * @return
	 * @throws FileNotFoundException
	 */
	private String getFileType(String filePath) throws FileNotFoundException {
		// 得到文件类型
		int dotPos = filePath.lastIndexOf(".") + 1;

		if (dotPos <= 0) {
			return null;
		}

		return filePath.substring(dotPos, filePath.length());
	}

	public void init(FilterConfig config) throws ServletException {
		String publicStr = config.getInitParameter(KEY_RESOUTCEFILTER_INITPARAS_PUBLIC);
		if (null != publicStr && !StringUtil.isNullOrEmpty(publicStr)) {
			this.publices = publicStr.split(",");
		} else {
			this.publices = new String[] { "/pub/" };
		}
		String excludeStr = config.getInitParameter(KEY_RESOUTCEFILTER_INITPARAS_EXCLUDE);
		if (null != excludeStr && !StringUtil.isNullOrEmpty(excludeStr)) {
			this.exclusions = excludeStr.split(",");
		}
		env = RequestUtil.getEnvBeanByNetwrok();
		env.setExclusions(exclusions);
		//permissionService = Ccay.getContext().getBean("personalPermissionService", IPersonalPermissionService.class);
		//applicationStateHandler = Ccay.getContext().getBean("applicationStateHandler", ApplicationStateHandler.class);
		hostDomainHandler = Ccay.getContext().getBean("hostDomainHandler", IHostDomainHandler.class);
	}

}
